package com.ark.security.service;

import com.ark.common.domain.entity.sys.SysLog;
import com.ark.common.domain.entity.sys.SysUser;
import com.ark.common.domain.model.LoginBody;
import com.ark.common.domain.model.LoginUser;
import com.ark.common.exception.ServiceException;
import com.ark.common.response.Result;
import com.ark.common.utils.IpUtils;
import com.ark.security.context.AuthenticationContextHolder;
import com.ark.service.service.SysLogService;
import com.ark.service.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

@Slf4j
@Component
public class LoginService {

    @Resource
    private TokenService tokenService;
    @Resource
    private SysUserService userService;
    @Resource
    private SysLogService logService;

    @Resource
    private AuthenticationManager authenticationManager;

    public String login(LoginBody loginBody, HttpServletRequest request) {
        // TODO: 登录验证码
        SysLog log = new SysLog();
        log.setIp(IpUtils.getIpAddr(request));
        log.setUsername(loginBody.getUsername());
        Authentication authentication = null;
        try {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginBody.getUsername(), loginBody.getPassword());
            authentication = authenticationManager.authenticate(authenticationToken);
            AuthenticationContextHolder.setContext(authentication);
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(authenticationToken);
        }catch (Exception e) {

            if (e instanceof BadCredentialsException){
                log.setDetails("用户名或密码错误！");
                insertLog(log);
                throw new ServiceException(Result.error("用户名或密码错误！"));
            }else {
                log.setDetails("登录失败！");
                insertLog(log);
                throw new ServiceException(Result.error("登录失败！"));
            }
        } finally {
            AuthenticationContextHolder.clearContext();
        }
        //取出登录用户
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        //添加登录日志
        log.setDetails("登录成功！");
        insertLog(log);
        //更新用户登录时间
        updateLoginTime(loginUser.getUserId());
        //生成Token
        return tokenService.createToken(loginUser);
    }

    /**
     * 添加登录日志
     *
     * @param log 日志
     */
    private void insertLog(SysLog log) {
        log.setLogTime(new Date());
        logService.insertLog(log);
    }

    /**
     * 更新登录时间，用于相同账号下一次登录最近登录的账号
     */
    private void updateLoginTime(Long userId) {
        SysUser user = new SysUser();
        user.setId(userId);
        user.setLoginTime(new Date());
        userService.updateUser(user);
    }
}
